package com.bckj.fastboot.core.extra.stage;

import com.bckj.fastboot.core.lang.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class StageChain<C extends BaseStageContext, S extends Stage<C>> {

    private final List<S> list;

    public StageChain(List<S> list) {
        this.list = list;
    }

    public static <C extends BaseStageContext, S extends Stage<C>> StageChain<C, S> newChain() {
        return new StageChain<>(new ArrayList<>());
    }

    public static <C extends BaseStageContext, S extends Stage<C>> StageChain<C, S> newChain(List<S> list) {
        return new StageChain<>(list);
    }

    @SafeVarargs
    public static <C extends BaseStageContext, S extends Stage<C>> StageChain<C, S> of(S ... stages) {
        return new StageChain<>(List.of(stages));
    }

    public StageChain<C, S> append(S stage) {
        list.add(stage);
        return this;
    }

    public void execute(C context) throws StageException {
        int index = 0;
        Exception error = null;
        for (; index < list.size(); index++) {
            Stage<C> stage = list.get(index);
            try {
                // 跳过判断
                if (stage.skip(context)) {
                    continue;
                }
                // 执行阶段
                stage.execute(context);
            } catch (StageException ex) {
                // 异常处理（优先调用补偿）
                if (stage instanceof CompensableStage<C> compensableStage) {
                    try {
                        compensableStage.compensate(context);
                    } catch (StageException compensateEx) {
                        // 记录补偿异常
                        ex.addSuppressed(compensateEx);
                    }
                }
                error = ex;
                // 终止
                break;
            } catch (Exception ex) {
                error = ex;
                // 终止
                break;
            }
        }
        if (error != null) {
            // 触发回滚
            for (int i = index - 1; i >= 0; i--) {
                Stage<C> stage = list.get(i);
                try {
                    stage.rollback(context, error);
                } catch (Exception e) {
                    log.error("回滚失败，class = " + stage.getClass().getSimpleName(), e);
                }
            }
            // 抛出异常
            if (error instanceof StageException stageException) {
                throw stageException;
            }
            throw new BusinessException(error.getMessage());
        }
        for (int i = index - 1; i >= 0; i--) {
            Stage<C> stage = list.get(i);
            try {
                stage.callback(context);
            } catch (Exception e) {
                log.error("回调失败，class = " + stage.getClass().getSimpleName(), e);
            }
        }
    }
}
